//--------------------------------------------------------------------------
// 
//  Copyright (c) Chili Software.  All rights reserved. 
// 
//  File: PersistentQueriesProvidersCollection.cs
//
//  Description: Holds a collection of IPersistentQueriesProviders.
// 
//--------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.ObjectModel;

namespace Chili.Opf3
{
	/// <summary>
	/// This class holds a list of <see cref="IPersistentQueriesProvider">IPersistentQueriesProviders</see>.
	/// </summary>
	public sealed class PersistentQueriesProvidersCollection : IDictionary<Type, IPersistentQueriesProvider>
	{
		private Dictionary<Type, IPersistentQueriesProvider> _providers = new Dictionary<Type, IPersistentQueriesProvider>();
		private IPersistentQueriesProvider _lastProvider;
		private Type _lastType;

		/// <summary>
		/// Adds an <see cref="IPersistentQueriesProvider">IPersistentQueriesProvider</see> to the <see cref="PersistentQueriesProvidersCollection">PersistentQueriesProvidersCollection</see>.
		/// </summary>
		/// <param name="value">The <see cref="IPersistentQueriesProvider">IPersistentQueriesProvider</see> to add.</param>
		public void Add(IPersistentQueriesProvider value)
		{
			if (value == null)
				throw new ArgumentNullException("value");

			// Add the provider.
			_providers.Add(value.PersistentType, value);
		}

		#region IDictionary<Type,IPersistentQueriesProvider> Members

		void IDictionary<Type, IPersistentQueriesProvider>.Add(Type key, IPersistentQueriesProvider value)
		{
			throw new NotSupportedException();
		}

		/// <summary>
		/// Determines whether the <see cref="PersistentQueriesProvidersCollection">PersistentQueriesProvidersCollection</see> contains an element with the specified key. 
		/// </summary>
		/// <param name="key">The persistent type to locate in the <see cref="PersistentQueriesProvidersCollection">PersistentQueriesProvidersCollection</see>.</param>
		/// <returns></returns>
		public bool ContainsKey(Type key)
		{
			return _providers.ContainsKey(key);
		}

		/// <summary>
		/// Gets an ICollection containing the keys of the <see cref="PersistentQueriesProvidersCollection">PersistentQueriesProvidersCollection</see>.
		/// </summary>
		public ICollection<Type> Keys
		{
			get { return _providers.Keys; }
		}

		/// <summary>
		/// Removes the element with the specified key from the <see cref="PersistentQueriesProvidersCollection">PersistentQueriesProvidersCollection</see>.
		/// </summary>
		/// <param name="key">The persistent type to remove from the <see cref="PersistentQueriesProvidersCollection">PersistentQueriesProvidersCollection</see>.</param>
		/// <returns></returns>
		public bool Remove(Type key)
		{
			// Set also the last type to null, if the last type is the one
			// that is going to be removed.
			if (_lastType == key)
			{
				_lastType = null;
				_lastProvider = null;
			}

			return _providers.Remove(key);
		}

		/// <summary>
		/// Gets the value associated with the specified type. 
		/// </summary>
		/// <param name="key">The persistent type whose value to get.</param>
		/// <param name="value">When this method returns, the value associated with the specified key, if the key is found; otherwise, 
		/// the default value for the type of the value parameter. This parameter is passed uninitialized.</param>
		/// <returns>true if the object that implements <see cref="PersistentQueriesProvidersCollection">PersistentQueriesProvidersCollection</see> contains an 
		/// element with the specified key; otherwise, false.</returns>
		public bool TryGetValue(Type key, out IPersistentQueriesProvider value)
		{
			// Check if the last type is the one that is requested.
			if (_lastType == key)
			{
				value = _lastProvider;
				return true;
			}

			// If not get the provider from the dictionary.
			bool result = _providers.TryGetValue(key, out value);
			// ... and store the result as the last type.
			if (result)
			{
				_lastType = key;
				_lastProvider = value;
			}

			return result;
		}

		/// <summary>
		/// Gets an ICollection containing the values in the <see cref="PersistentQueriesProvidersCollection">PersistentQueriesProvidersCollection</see>.
		/// </summary>
		public ICollection<IPersistentQueriesProvider> Values
		{
			get { return _providers.Values; }
		}

		/// <summary>
		/// Gets or sets the element with the specified type.
		/// </summary>
		/// <param name="key">The persistent type to get or set.</param>
		/// <returns>The element associated with the specified type or null if none is found.</returns>
		public IPersistentQueriesProvider this[Type key]
		{
			get
			{
				// Try to get the provider.
				IPersistentQueriesProvider provider = null;
				if (TryGetValue(key, out provider))
					return provider;

				// Return null if not possible.
				return null;
			}
			set
			{
				if (key != value.PersistentType)
					throw new InvalidOperationException("IPersistentQueriesProvider's persistent type does not match the given persistent type.");

				_providers[key] = value;
			}
		}

		#endregion

		#region ICollection<KeyValuePair<Type,IPersistentQueriesProvider>> Members

		void ICollection<KeyValuePair<Type,IPersistentQueriesProvider>>.Add(KeyValuePair<Type, IPersistentQueriesProvider> item)
		{
			throw new NotSupportedException();
		}

		/// <summary>
		/// Removes all items from the <see cref="PersistentQueriesProvidersCollection">PersistentQueriesProvidersCollection</see>.
		/// </summary>
		public void Clear()
		{
			_providers.Clear();
		}

		bool ICollection<KeyValuePair<Type, IPersistentQueriesProvider>>.Contains(KeyValuePair<Type, IPersistentQueriesProvider> item)
		{
			throw new NotSupportedException();
		}

		void ICollection<KeyValuePair<Type,IPersistentQueriesProvider>>.CopyTo(KeyValuePair<Type, IPersistentQueriesProvider>[] array, int arrayIndex)
		{
			throw new NotSupportedException();
		}

		/// <summary>
		/// Gets the number of elements contained in the <see cref="PersistentQueriesProvidersCollection">PersistentQueriesProvidersCollection</see>.
		/// </summary>
		public int Count
		{
			get { return _providers.Count; }
		}

		/// <summary>
		/// Gets a value indicating whether the <see cref="PersistentQueriesProvidersCollection">PersistentQueriesProvidersCollection</see> is read-only.
		/// </summary>
		public bool IsReadOnly
		{
			get { return false; }
		}

		bool ICollection<KeyValuePair<Type, IPersistentQueriesProvider>>.Remove(KeyValuePair<Type, IPersistentQueriesProvider> item)
		{
			throw new NotSupportedException();
		}

		#endregion

		#region IEnumerable<KeyValuePair<Type,IPersistentQueriesProvider>> Members

		/// <summary>
		/// Returns an enumerator for the <see cref="PersistentQueriesProvidersCollection">PersistentQueriesProvidersCollection</see>.
		/// </summary>
		/// <returns></returns>
		public IEnumerator<KeyValuePair<Type, IPersistentQueriesProvider>> GetEnumerator()
		{
			return _providers.GetEnumerator();
		}

		#endregion

		#region IEnumerable Members

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return ((System.Collections.IEnumerable)_providers).GetEnumerator();
		}

		#endregion
	}
}
